﻿using Gavel.Common.Utilities.Const;
using Gavel.Common.Utilities.Extension;

namespace Gavel.ModLink.Model;

/// <summary>
/// 请求帧基类
/// </summary>
public class RequestFrame : BaseFrame
{
    /// <summary>
    /// 从机地址
    /// </summary>
    public byte SlaveAddr { get; set; }

    /// <summary>
    /// 寄存器起始地址
    /// </summary>
    public ushort RegisterAddr { get; set; }

    /// <summary>
    /// 寄存器读取数量
    /// </summary>
    public ushort RegisterCount { get; set; }

    /// <summary>
    /// 获取报文
    /// </summary>
    public byte[] Message
    {
        get
        {
            byte[] frame;
            switch (Protocol)
            {
                case ProtocolType.Rtu:
                    frame = new byte[8];
                    frame[0] = SlaveAddr;
                    frame[1] = (byte)Function;
                    RegisterAddr.ToBytes().CopyTo(frame, 2);
                    RegisterCount.ToBytes().CopyTo(frame, 4);
                    frame[..6].CalculateCrc(Endian).CopyTo(frame, 6);
                    break;
                case ProtocolType.Tcp:
                default:
                    frame = new byte[12];
                    ushort index = (ushort)Random.Shared.Next(0, ushort.MaxValue);
                    index.ToBytes().CopyTo(frame, 0);
                    ((ushort)0).ToBytes().CopyTo(frame, 2);
                    ((ushort)6).ToBytes().CopyTo(frame, 4);
                    frame[6] = SlaveAddr;
                    frame[7] = (byte)Function;
                    RegisterAddr.ToBytes().CopyTo(frame, 8);
                    RegisterCount.ToBytes().CopyTo(frame, 10);
                    break;
            }

            return frame;
        }
    }

    /// <summary>
    /// 初始化构造
    /// </summary>
    /// <param name="protocol">协议类型</param>
    /// <param name="function">功能码</param>
    /// <param name="slaveAddr">从机地址（设备ID）</param>
    /// <param name="registerAddr">寄存器起始地址</param>
    /// <param name="registerCount">寄存器数量</param>
    /// <param name="endian">端类型</param>
    public RequestFrame(ProtocolType protocol, FunctionType function, byte slaveAddr, ushort registerAddr, ushort registerCount, Endian endian = Endian.Little)
    {
        Protocol = protocol;
        SlaveAddr = slaveAddr;
        RegisterAddr = registerAddr;
        RegisterCount = registerCount;
        Function = function;
        Endian = endian;
    }
}